package org.wmine.preprocess;

import java.util.Vector;
import javax.swing.table.DefaultTableModel;

public class Algorithm
{
	//Vector data;
	DefaultTableModel dtm;
	int columnindex;//,m,n;
	public  Algorithm(DefaultTableModel dt,int columnindex)
	{
		this.dtm=dt;
		this.columnindex=columnindex;
	
	}
	
	public int quickSort()
	{
		//System.out.flush();
		int i=q_sort(dtm, 0, dtm.getRowCount() - 1);
		
			
	  //System.out.print(dtm.getDataVector());
	  return i;
	}
	
	private int q_sort(DefaultTableModel dtm, int left, int right)
	
	{
		//System.out.println("dtm:"+dtm.getDataVector());
		float pivot;
		int l_hold, r_hold;
	  
		l_hold = left;
		r_hold = right;
	  
		pivot = Float.parseFloat(dtm.getValueAt(left,columnindex).toString());
	  
		//System.out.println("pivot:"+pivot);
		try
		{
			while (left < right)
			{
				while ((Float.parseFloat(dtm.getValueAt(right,columnindex).toString()) >= pivot) && (left < right))
					right--;
				if (left < right)
				{
					
					Vector v=dtm.getDataVector();
					
					Vector o1=(Vector)v.elementAt(left);
					Vector o2=(Vector)v.elementAt(right);
					/*v.set(left,o2);
					v.set(right,o1);*/
					dtm.removeRow(left);
					dtm.insertRow(left,o2);
					dtm.removeRow(right);
					dtm.insertRow(right,o1);
					
					left++;
				}
				while ((Float.parseFloat(dtm.getValueAt(left,columnindex).toString()) <= pivot) && (left < right))
						left++;
				if (left < right)
			    {
			    	Vector v=dtm.getDataVector();
					
					Vector o1=(Vector)v.elementAt(left);
					Vector o2=(Vector)v.elementAt(right);
					/*v.set(left,o2);
					v.set(right,o1);*/
					dtm.removeRow(left);
					dtm.insertRow(left,o2);
					dtm.removeRow(right);
					dtm.insertRow(right,o1);
			      right--;
			    }
			
				
			}
	 
			  int temp = left;
			  left = l_hold;
			  right = r_hold;
			  if (left < temp)
			    q_sort(dtm, left, temp-1);
			  if (right > temp)
			    q_sort(dtm, temp+1, right);
		}
		catch(Exception ee1)
		{
			return -1;
		}
		return 1;
		
	}

	private float CalculateMean(int i,int j)
	{
		float sum=0,mean=0;
		
			for(int k=i;k<=j;k++)
			{	
				sum+=Float.parseFloat(dtm.getValueAt(k,columnindex).toString().trim());
				PreprocessPanel.report.append(dtm.getValueAt(k,columnindex).toString()+" , ");
			}
			mean=sum/(j-i+1);
			System.out.println("i:"+i+" j: "+j+" mean:"+mean);
			PreprocessPanel.report.append(" ]<br> Mean : "+mean+"<br>");
			PreprocessPanel.report_summary.setText(PreprocessPanel.report.toString());
			PreprocessPanel.summary.repaint();
			
		return mean;
	}
	
	public float CalculateMean1(int i,int j)
	{
		float sum=0,mean=0;
		int cnt=0;
		try
		{
			PreprocessPanel.report.append("Values: [");
			for(int k=i;k<=j;k++)
			{
				if((dtm.getValueAt(k,columnindex)!=null) && !(dtm.getValueAt(k,columnindex).toString().trim().equals("?")) && !(dtm.getValueAt(k,columnindex).toString().trim().equals("")) )
				{	sum+=Float.parseFloat(dtm.getValueAt(k,columnindex).toString().trim());
					PreprocessPanel.report.append(dtm.getValueAt(k,columnindex).toString()+", ");
					
				}
				else
					cnt++;
			}
			mean=sum/(j-i+1-cnt);
			System.out.println("i:"+i+" j: "+j+" mean:"+mean);
			PreprocessPanel.report.append(" ]<br>Mean of Values: "+mean+"<br>");
			PreprocessPanel.report_summary.setText(PreprocessPanel.report.toString());
			PreprocessPanel.summary.repaint();
			
		}catch(Exception ee1)
		{
			System.out.print("exception in calmean1 "+ee1 );
			return -1;
		}
		
		return mean;
	}
	
	
	private float CalculateMedian(int i,int j,int bins)
	{
		float median=0,a2=0;
		
		// for forming report summary==> to display elements in a bin
		for(int k=i;k<=j;k++)
		{	
			//sum+=Float.parseFloat(dtm.getValueAt(k,columnindex).toString().trim());
			PreprocessPanel.report.append(dtm.getValueAt(k,columnindex).toString()+" , ");
		}
		
		float a1=Float.parseFloat(dtm.getValueAt((i+(j-i)/2),columnindex).toString().trim());
			
			if((dtm.getRowCount()/bins)%2==0)
			{
				
				a2=Float.parseFloat(dtm.getValueAt((i+(j-i)/2+1),columnindex).toString().trim());
				median= (a1+a2)/2;
			}
			else
				median=a1;
		
			PreprocessPanel.report.append(" ]<br>Median of Values: "+median+"<br>");
			PreprocessPanel.report_summary.setText(PreprocessPanel.report.toString());
			PreprocessPanel.summary.repaint();
			
		return median;
		
	}
	
	private float CalculateMedian_Width(int i,int j)
	{
		float median=0,a2=0;
		System.out.println("median_width>>> i::"+i+  "j::"+j);
		// for forming report summary==> to display elements in a bin
		for(int k=i;k<=j;k++)
		{	
			//sum+=Float.parseFloat(dtm.getValueAt(k,columnindex).toString().trim());
			PreprocessPanel.report.append(dtm.getValueAt(k,columnindex).toString()+" , ");
		}
		
		float a1=Float.parseFloat(dtm.getValueAt((i+(j-i)/2),columnindex).toString().trim());
			
			if((j-i+1)%2==0)
			{
				
				a2=Float.parseFloat(dtm.getValueAt((i+(j-i)/2+1),columnindex).toString().trim());
				median= (a1+a2)/2;
			}
			else
				median=a1;
		
			PreprocessPanel.report.append(" ]<br>Median of Values: "+median+"<br>");
			PreprocessPanel.report_summary.setText(PreprocessPanel.report.toString());
			PreprocessPanel.summary.repaint();
			
		return median;
		
	}
	
	private void CalulateBoundary(int i,int j)
	{
//		 for forming report summary==> to display elements in a bin
		for(int k=i;k<=j;k++)
		{	
			//sum+=Float.parseFloat(dtm.getValueAt(k,columnindex).toString().trim());
			PreprocessPanel.report.append(dtm.getValueAt(k,columnindex).toString()+" , ");
		}
		PreprocessPanel.report.append(" ]<br> After Smoothing : [ ");
		
			float min=Float.parseFloat(dtm.getValueAt(i,columnindex).toString().trim());
			float max=Float.parseFloat(dtm.getValueAt(j,columnindex).toString().trim());
			
			for(int k=i;k<=j;k++)
			{
				float a1=Float.parseFloat(dtm.getValueAt(k,columnindex).toString().trim())-min;
				float a2=max - Float.parseFloat(dtm.getValueAt(k,columnindex).toString().trim());
				
				System.out.println("min"+min+" max:"+max+ " a1:"+a1+"  a2:"+a2);
				if(a1<=a2)
				{
					dtm.setValueAt(min,k,columnindex);
					PreprocessPanel.report.append(dtm.getValueAt(k,columnindex)+" , ");
				}
				else
				{
					dtm.setValueAt(max,k,columnindex);
					PreprocessPanel.report.append(dtm.getValueAt(k,columnindex)+" , ");
				}
			}
			PreprocessPanel.report.append(" ]<br>");
			PreprocessPanel.report_summary.setText(PreprocessPanel.report.toString());
			PreprocessPanel.summary.repaint();
	}
	
	private void SmoothTable(float value,int i,int j)
	{
		for(int k=i;k<=j;k++)
			dtm.setValueAt(value,k,columnindex);
	}
	
	public int Smooth_By_Means_Median(int bins,String str,String type)
	{
		int cnt=1,i=0,j=-1;
		float min=0,max=0,rangefrom=0,rangeto=0,width=0;
		int rows=dtm.getRowCount();
		if(type.equals("depth"))
		{
			i=0;
			j=(rows/bins)-1;
		}
		else
		{
			min=Float.parseFloat(dtm.getValueAt(0,columnindex).toString());
			max=Float.parseFloat(dtm.getValueAt(rows-1,columnindex).toString());
			width=(max-min)/rows;
			rangefrom=min;
			rangeto=rangefrom+width;
			int m1=Math.round(min);
			int m2=Math.round(max);
			int mm=Math.round((m2-m1)/rows);
			bins=Math.round((m2-m1)/mm);
			System.out.println("bins "+bins);
			System.out.println("rangefrom "+rangefrom);
			System.out.println("rangeto "+rangeto);
		}
		PreprocessPanel.report.append("<br>You chose to perform binning: Type: <b> Smooth By "+str+"</b><br>");
		try
		{
			if(type.equals("depth"))
			{
				while(cnt<=bins)
				{
					PreprocessPanel.report.append("<br>Bin "+cnt+" : [ ");
					cnt++;
					float value=0;
					if(str.equals("mean"))
						value=CalculateMean(i,j);
					else if(str.equals("median"))
						value=CalculateMedian(i,j,bins);
					
					SmoothTable(value,i,j);
					
					i=j+1;
					if( (cnt==bins) && (rows%bins!=0))
					{	j=rows-1;
						System.out.print("in if"+(rows-1));
					}
					
					else 
						j=j+(rows/bins);
				}
			}
			else if(type.equals("width"))
			{
				while(max >= rangefrom)	
				{
					PreprocessPanel.report.append("<br>Bin "+cnt+" : Range:: "+rangefrom+"--"+rangeto+ " <br>Values [ ");
					cnt++;
					
					float value=0;
					if(str.equals("mean"))
					{
						j=-1;
						int index=0;
						for(index=i;index<rows;index++)
						{
							
							if(Float.parseFloat(dtm.getValueAt(index,columnindex).toString()) < rangeto)
							{
								j=index;	
							}
							else 
							{
								break;
							}
						}
						if(j!=-1)
						{
							value=CalculateMean(i,j);
						}
						else
						{
							// bin is empty
							PreprocessPanel.report.append(" empty ]<br>");
							PreprocessPanel.report_summary.setText(PreprocessPanel.report.toString());
							PreprocessPanel.summary.repaint();
						}
						
						i=index;
						rangefrom=rangeto;
						rangeto=rangefrom+width;
						System.out.println("i:: "+i);
						System.out.println("j:: "+j);
						System.out.println("rangefrom "+rangefrom);
						System.out.println("rangeto "+rangeto);
					}
					else if(str.equals("median"))
					{
						j=-1;
						int index=0;
						for(index=i;index<rows;index++)
						{
							
							if(Float.parseFloat(dtm.getValueAt(index,columnindex).toString()) <rangeto)
							{
								j=index;	
							}
							else 
							{
								break;
							}
						}
						if(j!=-1)
						{
							value=CalculateMedian_Width(i,j);
						}
						else
						{
							// bin is empty
							PreprocessPanel.report.append(" empty ]<br>");
							PreprocessPanel.report_summary.setText(PreprocessPanel.report.toString());
							PreprocessPanel.summary.repaint();
						}
						
						i=index;
						rangefrom=rangeto;
						rangeto=rangefrom+width;
						System.out.println("i:: "+i);
						System.out.println("j:: "+j);
						System.out.println("rangefrom "+rangefrom);
						System.out.println("rangeto "+rangeto);
					}
					SmoothTable(value,i,j);
				
				}
			}
			
		}
		catch(Exception ee2)
		{
			System.out.println("error in smooth mean-median");
			return -1;
		}
		return 1;
	}

	
	public int Smooth_By_Boundary(int bins,String type)
	{
		int cnt=1;
		int i=0,j=-1;
		float min=0,max=0,rangefrom=0,rangeto=0;
		float temp=0;
		int rows=dtm.getRowCount();
		if(type.equals("depth"))
			j=(rows/bins)-1;
		else
		{
			min=Float.parseFloat(dtm.getValueAt(0,columnindex).toString());
			max=Float.parseFloat(dtm.getValueAt(rows-1,columnindex).toString());
			temp=(max-min);
			rangefrom=min;
			rangeto=rangefrom+(temp/rows)-1;
			int m1=Math.round(min);
			int m2=Math.round(max);
			int mm=Math.round(temp/rows);
			bins=Math.round(temp/mm)+1;
			System.out.println("bins::"+bins);
		}
		PreprocessPanel.report.append("<br>You chose to perform binning: Type: <b> Smooth By Boundary</b><br>");
		try
		{
			while(cnt<=bins)
			{
				if(type.equals("depth"))
					PreprocessPanel.report.append("<br>Bin "+cnt+" : [ ");
				else if(type.equals("width"))
					PreprocessPanel.report.append("<br>Bin "+cnt+" : Range:: "+rangefrom+"--"+rangeto+ " <br>Values [ ");
				cnt++;
				
				if(type.equals("depth"))
				{
					CalulateBoundary(i,j);
					i=j+1;
					if( (cnt==bins) && (rows%bins!=0))
					{	
						j=rows-1;
					}
					
					else 
						j=j+(rows/bins);
				}
				
				else if(type.equals("width"))
				{
					j=-1;
					int index=0;
					for(index=i;index<rows;index++)
					{
						
						if(Float.parseFloat(dtm.getValueAt(index,columnindex).toString()) <=rangeto)
						{
							j=index;	
						}
						else 
						{
							break;
						}
					}
					if(j!=-1)
					{
						CalulateBoundary(i,j);
					}
					else
					{
						// bin is empty
						PreprocessPanel.report.append(" empty ]<br>");
						PreprocessPanel.report_summary.setText(PreprocessPanel.report.toString());
						PreprocessPanel.summary.repaint();
					}
					
					i=index;
					rangefrom=rangeto+1;
					rangeto=rangefrom+((max-min)/rows)-1;
					System.out.println("i:: "+i);
					System.out.println("j:: "+j);
					System.out.println("rangefrom "+rangefrom);
					System.out.println("rangeto "+rangeto);
				}
				
				
			}
		}catch(Exception ee2)
		{
			System.out.println("error in boundary");
			return -1;
		}
		return 1;
	}
}